<?php

declare(strict_types=1);

namespace App\CustHub\Service;

use App\CustHub\Constants\CtrlRoomListeningContentConstants;
use App\CustHub\Constants\MsgTypeConstants;
use App\CustHub\Mapper\ChChatRecordMapper;
use App\CustHub\Mapper\ChContactMapper;
use App\CustHub\Mapper\ChCtrlRoomSchemeCfgMapper;
use App\CustHub\Mapper\ChCtrlRoomSchemeMapper;
use App\CustHub\Mapper\ChRobotMapper;
use App\CustHub\Mapper\ChRoomMapper;
use App\CustHub\Mapper\ChRoomMemberMapper;
use App\CustHub\Model\ChChatRecord;
use App\CustHub\Model\ChContact;
use App\CustHub\Model\ChCtrlRoomFilterRule;
use App\CustHub\Model\ChCtrlRoomScheme;
use App\CustHub\Model\ChCtrlRoomSchemeCfg;
use App\CustHub\Model\ChRobot;
use App\CustHub\Model\ChRoom;
use App\CustHub\Model\ChRoomMember;
use App\Robot\Dto\CommonJobDto;
use App\Robot\Dto\RobotMsgDto;
use App\Robot\Job\CommonJob;
use App\Robot\Job\SendRobotMsgDelayedJob;
use App\Robot\Service\SendRobotMessageService;
use App\Setting\Service\SettingConfigService;
use Carbon\Carbon;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Redis\Redis;
use Mine\Abstracts\AbstractService;
use Mine\Annotation\Transaction;
use Mine\Exception\NormalStatusException;
use Mine\MineModel;
use function Hyperf\Collection\data_get;

/**
 * 中控群方案服务类
 */
class ChCtrlRoomSchemeService extends AbstractService
{
    public $mapper;

    private const CTRL_REPLY_IMG_KEY = 'ctrl_reply_img:';

    #[Inject]
    protected ChCtrlRoomSchemeCfgMapper $schemeCfgMapper;

    #[Inject]
    protected ChContactMapper $contactMapper;

    #[Inject]
    protected ChRoomMapper $roomMapper;

    #[Inject]
    protected ChRoomMemberMapper $roomMemberMapper;

    #[Inject]
    protected ChRobotMapper $robotMapper;

    #[Inject]
    protected Redis $redis;

    #[Inject]
    protected ChCtrlRoomFilterRuleService $filterRuleService;

    public function __construct(ChCtrlRoomSchemeMapper $mapper)
    {
        $this->mapper = $mapper;
    }

    public function getSchemePageList(array $params): array
    {
        $pageSize =  $params['page_size'] ?? MineModel::PAGE_SIZE;
        $mainUid = $params['main_uid'];
        $p = ChCtrlRoomScheme::query()
            ->select(['id','robot_type','room_wxid','remark','robot_count','status'])
            ->with(['room'=>function ($query) {
                $query->select(['id','room_name','room_avatar_url','room_wxid']);
            }])
            ->where('main_uid',$mainUid)
            ->whereHas('room',function ($query) use ($mainUid){
                $query->where('main_uid',$mainUid);
            })
            ->orderByDesc('created_at')
            ->paginate((int)$pageSize);

        return $this->mapper->setPaginate($p);
    }

    #[Transaction]
    public function saveScheme(array $data): mixed
    {
        $data['listening_content'] = json_decode($data['listening_content'], true);
        $msgSource = json_decode($data['msg_source'], true);
        $robotCount = count($msgSource);
        $data['robot_count'] = $robotCount;

        $schemeId = $this->mapper->save($data);
        if (!$schemeId) {
            throw new NormalStatusException('操作失败');
        }
        $msgSource = $this->getMsgSource($msgSource, $schemeId);
        $msgSourceData = [];
        foreach ($msgSource as $value){
            $this->schemeCfgMapper->filterExecuteAttributes($value,true);
            $msgSourceData[] = $value;
        }
        return $this->schemeCfgMapper->model::insert($msgSourceData);
    }

    /**
     * 方案信息
     * @param array $data
     * @return \App\CustHub\Model\ChCtrlRoomScheme|\Hyperf\Database\Model\Model|array|string|\Hyperf\Database\Model\Builder
     */
    public function getInfo(array $data): \App\CustHub\Model\ChCtrlRoomScheme|\Hyperf\Database\Model\Model|array|string|\Hyperf\Database\Model\Builder
    {
        $schemeId = (int)$data['id'];
        $schemeInfo = $this->mapper->findById($schemeId);
        if(empty($schemeInfo)){
            throw new NormalStatusException('请选择方案');
        }

        $roomInfo = $this->roomMapper->findByRoomWxid($schemeInfo['room_wxid'],$schemeInfo->main_uid);
        $schemeInfo->room_name = $roomInfo->room_name ?? '';
        $schemeInfo->room_avatar_url = $roomInfo->room_avatar_url ?? '';

        $schemeConfigs = ChCtrlRoomSchemeCfg::query()
            ->with(['robot'=>function ($query) {
                $query->select(['id','nickname','avatar']);
            }])
            ->where('scheme_id',$schemeId)
            ->get()->toArray();

        foreach ($schemeConfigs as $key => $value){
            $schemeConfigs[$key]['contact_list'] = [];
            $robotId = $value['robot_id'];
            if($value['cust_mon_scope'] ==1 && !empty($value['cust_scope_config'])){
                $userIds = $value['cust_scope_config'];
                $contactList = ChContact::query()
                    ->select(['id','nickname','avatar','user_id'])
                    ->where('robot_id',$robotId)
                    ->whereIn('user_id',$userIds)
                    ->get();
                $schemeConfigs[$key]['contact_list'] = $contactList;
            }elseif($value['cust_mon_scope'] == 0 && !empty($value['cust_exclude_config']['ids'])){
                $contactList = ChContact::query()
                    ->select(['id','nickname','avatar','user_id'])
                    ->where('robot_id',$robotId)
                    ->whereIn('user_id',$value['cust_exclude_config']['ids'])
                    ->get();
                $schemeConfigs[$key]['contact_list'] = $contactList;
            }

            $schemeConfigs[$key]['room_list'] = [];
            $schemeConfigs[$key]['room_member_list'] = [];
            if($value['room_mon_scope'] == 1 && !empty($value['room_scope_config'])){
                $roomWxids = $value['room_scope_config'];
                $roomList = ChRoom::query()
                    ->select(['id','room_name','room_avatar_url','room_wxid','room_member_count'])
                    ->whereIn('room_wxid',$roomWxids)
                    ->whereHas('robots',function ($query) use ($robotId){
                        $query->where('robot_id',$robotId);
                    })
                    ->get();
                $schemeConfigs[$key]['room_list'] = $roomList;
            }elseif($value['room_mon_scope'] == 0 && !empty($value['room_exclude_config']['ids'])){
                $roomMemberList = ChRoomMember::query()
                    ->select(['id','nickname','avatar','user_id'])
                    ->whereIn('user_id',$value['room_exclude_config']['ids'])
                    ->whereHas('room',function ($query) use ($robotId){
                        $query->whereHas('robots',function ($query) use ($robotId){
                            $query->where('robot_id',$robotId);
                        });
                    })
                    ->groupBy('user_id')
                    ->get();
                $schemeConfigs[$key]['room_member_list'] = $roomMemberList;
            }
        }
        $schemeInfo['msg_source'] = $schemeConfigs;
        return $schemeInfo;
    }

    #[Transaction]
    public function updateScheme(array $data):bool
    {
        $schemeId = (int)$data['id'];
        $schemeInfo = $this->mapper->findById($schemeId);
        if(empty($schemeInfo)){
            throw new NormalStatusException('请选择方案');
        }

        $data['listening_content'] = json_decode($data['listening_content'], true);

        $msgSource = json_decode($data['msg_source'], true);
        $msgSource = $this->getMsgSource($msgSource, $schemeId);
        $data['robot_count'] = count($msgSource);

        $rst = $this->mapper->update($schemeId,$data);
        if (!$rst) {
            throw new NormalStatusException('操作失败');
        }


        $schemeConfigs = ChCtrlRoomSchemeCfg::query()
            ->select(['id','scheme_id','robot_id'])
            ->where('scheme_id',$schemeId)
            ->get();
        $schemeConfigs = $schemeConfigs->map(function ($item){
            $item['key'] = $item['scheme_id'].'_'.$item['robot_id'];
            return $item;
        })->pluck('id','key')->toArray();


        $toUpdate = [];
        $toInsert = [];
        foreach ($msgSource as $value){
            $this->schemeCfgMapper->filterExecuteAttributes($value,true);
            $key = $value['scheme_id'].'_'.$value['robot_id'];
            if(isset($schemeConfigs[$key])){
                unset($value['created_at']);
                $value['id'] = $schemeConfigs[$key];
                $toUpdate[] = $value;
            }else{
                $toInsert[] = $value;
            }
        }

        $existIds = array_values($schemeConfigs);
        $toUpdateIds = [];
        if(!empty($toUpdate)){
            $toUpdateIds = array_column($toUpdate,'id');
            $this->schemeCfgMapper->model::upsert($toUpdate,['id']);
        }

        if(!empty($toInsert)){
            $this->schemeCfgMapper->model::insert($toInsert);
        }

        $toDeleteIds = array_diff($existIds,$toUpdateIds);
        if(!empty($toDeleteIds)){
            ChCtrlRoomSchemeCfg::query()->whereIn('id',$toDeleteIds)->delete();
        }
        $this->mapper->delCache($schemeId);
        return true;
    }

    /**
     * 删除方案
     * @param array $params
     * @return bool
     * @throws \Exception
     */
    #[Transaction]
    public function deleteScheme(array $params): bool
    {
        $schemeId = (int)$params['id'];
        $scheme = $this->mapper->findById($schemeId);
        if(empty($scheme)){
            throw new NormalStatusException('请选择方案');
        }

        $scheme->delete();

        $robotIds = $this->schemeCfgMapper->model::query()
            ->where('scheme_id',$schemeId)
            ->pluck('robot_id')->toArray();

        $this->schemeCfgMapper->model::query()
            ->where('scheme_id',$schemeId)
            ->delete();

        foreach ($robotIds as $robotId){
            $this->schemeCfgMapper->delCache($robotId);
        }

        $this->mapper->delCache($schemeId);
        return true;
    }

    public function changeStatus(mixed $id, string $value, string $filed = 'status'): bool
    {
        $robotIds = $this->schemeCfgMapper->model::query()
            ->where('scheme_id',(int)$id)
            ->pluck('robot_id')->toArray();

        foreach ($robotIds as $robotId){
            $this->schemeCfgMapper->delCache($robotId);
        }

        $this->mapper->delCache((int)$id);

        return $value == MineModel::ENABLE ? $this->mapper->enable([$id], $filed) : $this->mapper->disable([$id], $filed);
    }

    /**
     * 修改备注
     * @param array $data
     * @return bool
     */
    public function editRemark(array $data):bool
    {
        $scheme = $this->mapper->findById((int)$data['id']);
        if(empty($scheme)){
            throw new NormalStatusException('请选择方案');
        }
        $scheme->remark = $data['remark'];
        $rst = $scheme->save();
        $this->mapper->delCache($scheme->id);
        return $rst;
    }

    /**
     * 复制方案
     * @param array $params
     * @return mixed
     */
    #[Transaction]
    public function copy(array $params):mixed
    {
        $scheme = $this->mapper->findById((int)$params['id']);
        if(empty($scheme)){
            throw new NormalStatusException('请选择方案');
        }

        $data = $scheme->toArray();
        unset($data['id'],$data['created_at'],$data['updated_at']);
        $id = $this->mapper->save($data);

        $msgSource = ChCtrlRoomSchemeCfg::query()
            ->where('scheme_id',$params['id'])
            ->get()
            ->toArray();

        $msgSource = $this->getMsgSource($msgSource, $id);

        foreach ($msgSource as $k=>$value){
            $msgSource[$k]['created_at'] = $msgSource[$k]['updated_at'] = Carbon::now();
            unset($msgSource[$k]['id']);
        }
        return $this->schemeCfgMapper->model::insert($msgSource);
    }

    public function saveRule(array $data): bool
    {
        if(!empty($data['customer_filter'])){
            $data['customer_filter'] = json_decode($data['customer_filter'],true);
        }

        if(!empty($data['keyword_rule'])){
            $data['keyword_rule'] = json_decode($data['keyword_rule'],true);
        }

        return $this->filterRuleService->saveRule($data);
    }

    public function getRuleInfo(array $params): ChCtrlRoomFilterRule|\Hyperf\Database\Model\Builder|null
    {
        return $this->filterRuleService->findByMainUid($params['main_uid']);
    }

    /**
     * 获取消息来源
     * @param array $data
     * @param $schemeId
     * @return array|mixed
     */
    private function getMsgSource(array $msgSource, $schemeId): mixed
    {
        foreach ($msgSource as $key => $value) {
            $msgSource[$key]['scheme_id'] = $schemeId;
            $msgSource[$key]['cust_exclude_config'] = isset($value['cust_exclude_config']) ? json_encode($value['cust_exclude_config']) : json_encode(['switch'=>0,'ids'=>[]]);
            $msgSource[$key]['cust_scope_config'] = isset($value['cust_scope_config']) ? json_encode($value['cust_scope_config']) : json_encode([]);
            $msgSource[$key]['room_exclude_config'] = isset($value['room_exclude_config']) ? json_encode($value['room_exclude_config']) : json_encode(['switch'=>0,'ids'=>[]]);
            $msgSource[$key]['room_scope_config'] = isset($value['room_scope_config']) ? json_encode($value['room_scope_config']) : json_encode([]);
            $msgSource[$key]['created_at'] = $msgSource[$key]['updated_at'] = Carbon::now();
            $this->schemeCfgMapper->delCache((int)$value['robot_id']);
        }
        return $msgSource;
    }


    public function handle(ChRobot $robot, array $data)
    {
        $robotId = $robot->id;

        $userId = $data['sender'];
        $isRoom = $data['is_room'];
        $roomWxid = $isRoom ? $data['from_room_id'] : '';
        $roomName = '';
        if($isRoom){
            $contact = $this->roomMemberMapper->findByRoomWxidAndUserId($roomWxid,$userId);
            $roomInfo = $this->roomMapper->findByRoomWxid($roomWxid,$robot->main_uid);
            $roomName = empty($roomInfo->room_name) ? '未设置群名' : $roomInfo->room_name;
            $text = '发送者';
        }else{
            $contact = $this->contactMapper->findByRobotIdAndUserId($robotId,$userId);
            $text = '客户';
        }
        if(empty($contact)){
            return;
        }

        $senderName = $contact->nickname;

        //根据机器人查询是否有满足条件的中控群方案
        $list = $this->schemeCfgMapper->getSchemeListByRobot($robotId);
        $ctrlRoomWxids = [];
        $listeningType = CtrlRoomListeningContentConstants::getListeningContent($data['msgtype']);

        //聊天记录ID
        $chatRecordId = $data['chat_record_id'];

        foreach ($list as $item) {

            if(!in_array($listeningType,$item->scheme->listening_content)){
                continue;
            }

            if($isRoom){
                $room_mon_scope = $item->room_mon_scope;
                if($room_mon_scope == 2){
                    continue;
                }elseif ($room_mon_scope == 1){
                    $room_scope_config = $item->room_scope_config;
                    if(!in_array($roomWxid, $room_scope_config)){
                        continue;
                    }
                }elseif ($room_mon_scope == 0){
                    $room_exclude_config = $item->room_exclude_config;
                    if($room_exclude_config['switch'] == 1 && in_array($userId, $room_exclude_config['ids'])){
                        continue;
                    }
                }

                if($roomWxid == $item->scheme->room_wxid){
                    continue;
                }

            }else{
                $cust_mon_scope = $item->cust_mon_scope;
                if($cust_mon_scope == 2){
                    continue;
                }elseif ($cust_mon_scope == 1){
                    $cust_scope_config = $item->cust_scope_config;
                    if(!in_array($userId, $cust_scope_config)){
                        continue;
                    }
                }elseif ($cust_mon_scope == 0){
                    $cust_exclude_config = $item->cust_exclude_config;
                    if($cust_exclude_config['switch'] == 1 && in_array($userId, $cust_exclude_config['ids'])){
                        continue;
                    }
                }
            }

            $is_auto_at_cust = $item->scheme->is_auto_at_cust;
            if($is_auto_at_cust){
                ChChatRecord::query()->where('id',$chatRecordId)->update(['is_auto_at_cust'=>1]);
            }

            $ctrlRoomWxids[] = $item->scheme->room_wxid;
        }

        foreach ($ctrlRoomWxids as $roomWxid){
            $roomInfo = ChRoom::query()
                ->select(['id','room_wxid','room_name'])
                ->with(['robots' => function ($query) {
                    $query->select(['id','robot_key','server_id']);
                }])
                ->where('main_uid',$robot->main_uid)
                ->where('room_wxid',$roomWxid)
                ->whereHas('robots',function ($query){
                    $query->where('login_status',1);
                })->first();

            if(!empty($roomInfo)){
                $sender = $senderName;
                $jkz = $robot->nickname;
                $content = CtrlRoomListeningContentConstants::getMessage($listeningType);
                //往中控群中发送消息
                $roomTpl = '';
                if(!empty($roomName)){
                    $roomTpl = "群：{$roomName}\n";
                }


                $roomTpl = $roomTpl."{$text}：{$sender}\n监控者：{$jkz}\n编号：{$chatRecordId}\n===============\n内容：{$content}";

                $msgContents[] = [
                    'msg_type' => MsgTypeConstants::TEXT,
                    'msg_content' => $roomTpl,
                ];

                $msgType = MsgTypeConstants::getMsgType($data['msgtype']);
                switch ($msgType) {
                    case MsgTypeConstants::TEXT:
                        $msgContents[] = [
                            'msg_type' => MsgTypeConstants::TEXT,
                            'msg_content' => $data['content']['content'],
                        ];
                        break;
                    case MsgTypeConstants::IMAGE:
                        $msgContents[] = [
                            'msg_type' => MsgTypeConstants::IMAGE,
                            'msg_content' => $data['content']['content'],
                        ];
                        break;
                    case MsgTypeConstants::EMOJI:
                        $msgContents[] = [
                            'msg_type' => MsgTypeConstants::EMOJI,
                            'msg_content' => $data['content']['content'],
                        ];
                        break;
                    case MsgTypeConstants::VIDEO:
                        $msgContents[] = [
                            'msg_type' => MsgTypeConstants::VIDEO,
                            'msg_content' => $data['content']['content'],
                        ];
                        break;
                    case MsgTypeConstants::MINI_PROGRAM:
                        $msgContents[] = [
                            'msg_type' => MsgTypeConstants::MINI_PROGRAM,
                            'msg_content' => $data['msg_data'],
                        ];
                        break;
                    case MsgTypeConstants::URL:
                        $msgData = $data['msg_data'];
                        $sendContent['title'] = decodeIfBase64($msgData['title']);
                        $sendContent['desc'] = decodeIfBase64($msgData['desc']);
                        $sendContent['url'] = $msgData['link_url'];
                        $sendContent['cover'] = $msgData['icon_url'];

                        $msgContents[] = [
                            'msg_type' => MsgTypeConstants::URL,
                            'msg_content' => $sendContent,
                        ];
                        break;
                    case MsgTypeConstants::VIDEO_CHANNEL:
                        $msgContents[] = [
                            'msg_type' => MsgTypeConstants::VIDEO_CHANNEL,
                            'msg_content' => $data['msg_data'],
                        ];
                        break;
                    default:
                        break;
                }
                stdout_log()->info("中控群监听消息：".json_encode($msgContents,JSON_UNESCAPED_UNICODE));
                //发送消息到中控群
                $roomRobot = $roomInfo->robots()->first();
                $delay = 0;
                foreach ($msgContents as $k => $msgContent) {
                    $msgData = new RobotMsgDto();
                    $msgData->setMsgType($msgContent['msg_type'])
                        ->setContent($msgContent['msg_content'])
                        ->setToId($roomWxid)
                        ->setServerId($roomRobot->server_id)
                        ->setUuid($roomRobot->uuid);

                    if($k > 0){
                        $delay =  $delay + rand(2,5);
                    }
                    container()->get(LowQueueService::class)->push(new SendRobotMsgDelayedJob($msgData),$delay);
                }
            }
        }
    }

    public function replyMessage(ChRobot $robot,array $data)
    {
        if(isset($data['isWin'])){
            if($data['msgtype'] == 2){
                $content = data_get($data,'quoto','');
            }else{
                $content = $data['content'];
            }
        }else{
            $content = data_get($data,'msg_data.reply.content','');
            $replyContent =  data_get($data,'msg_data.content','');
        }


        $roomWxid = $data['from_room_id'];

        $ctrlReplyImgKey = self::CTRL_REPLY_IMG_KEY.$roomWxid;


        if(!str_contains($content,"编号：") || !str_contains($content,"监控者：")){
            return;
        }

        $exists = $this->mapper->checkExists($robot->main_uid,$roomWxid);
        if(!$exists){
            return;
        }

        $array = preg_split('/\r\n|\n|\r/', $content);

        $chatRecordId = null;
        //回复内容
        empty($replyContent) && $replyContent = end($array);
        foreach ($array as $line) {
            if (str_contains($line, '编号：')) {
                // 找到“编号”行，提取后面的值
                $chatRecordId = (int)trim(str_replace('编号：', '', $line));
                break;
            }
        }

        $chatRecordInfo = ChChatRecord::query()
            ->select(['id','robot_id','from_room_id','is_room','sender','is_auto_at_cust'])
            ->where('id',$chatRecordId)
            ->first();

        if(empty($chatRecordInfo)){
            return;
        }

        if($chatRecordInfo->is_room){
            $toId = $chatRecordInfo->from_room_id;
        }else{
            $toId = (string)$chatRecordInfo->sender;
        }
        $sendMessage = true;
        $ctrlRoomCommand = container()->get(SettingConfigService::class)->getConfigByKey('ctrl_room_command');
        if(!empty($ctrlRoomCommand)){
            $command = json_decode($ctrlRoomCommand['value'],true);
            foreach ($command as $item) {
                if($item['value'] == $replyContent && $item['key'] == 'send_img'){
                    //发送图片
                    $sendMessage = false;
                    $this->redis->set($ctrlReplyImgKey,[
                        'to_id' => $toId,
                        'robot_id' => $chatRecordInfo->robot_id,
                    ],3 * 60);
                }
            }
        }

        if($sendMessage){
            if($chatRecordInfo->is_auto_at_cust && $chatRecordInfo->is_room){
                $msgType = MsgTypeConstants::MIXED_TEXT;
                $content = [
                    [
                        'subtype'=>1,
                        'text'=> (string)$chatRecordInfo->sender,
                    ],
                    [
                        'subtype' => 0,
                        'text' => ' '.$replyContent
                    ]
                ];
            }else{
                $msgType = MsgTypeConstants::TEXT;
                $content = $replyContent;
            }
            container()->get(SendRobotMessageService::class)->handle([
                'robot_id' => $chatRecordInfo->robot_id,
                'msg_type' => $msgType,
                'content' => $content,
                'to_id' => $toId
            ]);
        }
    }

    /**
     * 回复图片内容
     * @param array $data
     * @return void
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function replyImg(array $data): void
    {
        $roomWxid = $data['from_room_id'];
        $ctrlReplyImgKey = self::CTRL_REPLY_IMG_KEY.$roomWxid;

        $replyInfo = $this->redis->get($ctrlReplyImgKey);
        if(!empty($replyInfo)){
            container()->get(SendRobotMessageService::class)->handle([
                'robot_id' => $replyInfo['robot_id'],
                'msg_type' => MsgTypeConstants::IMAGE,
                'content' => $data['content'],
                'to_id' => $replyInfo['to_id']
            ]);
            $this->redis->del($ctrlReplyImgKey);
        }
    }
}